package com.changgou.search.service.impl;

import changgou.itheima.service.SkuInfo;
import com.alibaba.fastjson.JSON;
import com.changgou.search.service.SearchSevice;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchSevice {
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    //每页数据条数
    public final static Integer pageSize = 20;
    //当前页面
    private int page = 0;
    //默认排序字段
    public String sortField = "updateTime";
    //默认排序方法
    public SortOrder sortRule = SortOrder.ASC;
    /**
     * 将spce的json数据转为Map<Set<>>
     * @param spceList
     * @return
     */
    public Map<String, Set<String>> paseJSONSpec(List<String> spceList){
        Map<String, Set<String>> spces = new HashMap<>();
        for (String s : spceList) {
            //json转map
            Map<String,String> map = JSON.parseObject(s, Map.class);
            Set<String> spceKeys = map.keySet();
            for (String spceKey : spceKeys) {
                Set<String> spceSet = spces.get(spceKey);
                if (spceSet==null){
                    spceSet=new HashSet<String>();
                    spces.put(spceKey,spceSet);
                }
                spceSet.add(map.get(spceKey));
            }
        }
        return spces;
    }

    /**
     * 全文搜索
     * @param searchMap
     * @return
     * @throws Exception
     */
    @Override
    public Map search(Map<String, String> searchMap) throws Exception {
        //构建结果Map
        HashMap<String, Object> resultMap = new HashMap<>();
        //有条件才查询 es
        if(searchMap!=null){
            //组合条件对象
            //BoolQueryBuilder用于多个查询条件组合
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            if (!StringUtils.isEmpty(searchMap.get("keywords"))){
                boolQuery.must(QueryBuilders.matchQuery("name",searchMap.get("keywords")).operator(Operator.OR));
            }
            //按照品牌查询
            if (!StringUtils.isEmpty(searchMap.get("brand"))){
                boolQuery.filter(QueryBuilders.termQuery("brandName",searchMap.get("brand")));
            }
            //按照规格进行过滤查询
            for (String key : searchMap.keySet()) {
                if(key.startsWith("spec_")){
                   boolQuery.filter(QueryBuilders.termQuery("specMap."+key.substring(5)+".keyword",searchMap.get(key)));
                }
            }
            //按照价格区间过滤查询
            if(!StringUtils.isEmpty(searchMap.get("price"))){
                String[] prices = searchMap.get("price").split("-");
                if (prices.length==2){
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }

            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            nativeSearchQueryBuilder.withQuery(boolQuery);
            //高亮查询
            HighlightBuilder.Field field = new HighlightBuilder
                    .Field("name")
                    .preTags("<span style= 'color : red;' >")
                    .postTags("</span>");
            nativeSearchQueryBuilder.withHighlightFields(field);
            //根据品牌的聚合查询
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skubrand").field("brandName"));
            //根据规格的聚合查询
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuspec").field("spec.keyword"));
            //分页查询
            if (!StringUtils.isEmpty(searchMap.get("page"))){
                page = Integer.parseInt(searchMap.get("page"))-1;
            }
            nativeSearchQueryBuilder.withPageable(PageRequest.of(page,pageSize));
            //根据返回数据sortField排序
            if(!StringUtils.isEmpty(searchMap.get("sortField"))){
                sortField=searchMap.get("sortField");
                if ("DESC".equals(searchMap.get("sortRule"))){
                    sortRule= SortOrder.DESC;
                }
            }
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField).order(sortRule));
            /**
             * 条件构建对象
             * 查询操作实体类
             * 查询结果操作对象
             */
            AggregatedPage<SkuInfo> aggregatedPage = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                    //查询结果操作
                    ArrayList<T> list = new ArrayList<>();
                    //获取查询命中的数据
                    SearchHits hits = response.getHits();
                    if (hits!=null){
                        //有查询结果
                        for (SearchHit hit : hits) {
                            SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
                            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                            if (highlightFields!=null&&highlightFields.size()>0){
                                skuInfo.setName(highlightFields.get("name").getFragments()[0].toString());
                            }
                            list.add((T) skuInfo);
                        }
                    }
                    return new AggregatedPageImpl<T>(list,pageable,hits.getTotalHits(),response.getAggregations());
                }
            });
            resultMap.put("total",aggregatedPage.getTotalElements());
            resultMap.put("totalPages",aggregatedPage.getTotalPages());
            resultMap.put("rows",aggregatedPage.getContent());
            StringTerms skubrands =(StringTerms) aggregatedPage.getAggregation("skubrand");
            List<String> brandList = skubrands.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            StringTerms skuspec = (StringTerms) aggregatedPage.getAggregation("skuspec");
            List<String> specList = skuspec.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("specList",paseJSONSpec(specList));
            resultMap.put("skubrand",brandList);
            return resultMap;
        }

        //封装最终的返回结果
        return null;
    }
}
